﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using SLogo.Drawing;

namespace SLogo.Command
{
    /// <summary>
    /// 绘图命令，处理与海龟有关的动作
    /// </summary>
    class TurtleCommand
    {
        /// <summary>
        /// 海龟水平位置
        /// </summary>
        public static double X { get; private set; }
        /// <summary>
        /// 海龟竖直位置
        /// </summary>
        public static double Y { get; private set; }
        /// <summary>
        /// 海龟朝向角度
        /// </summary>
        public static double H { get; private set; }
        /// <summary>
        /// 是否落笔
        /// </summary>
        public static bool IsDrawing { get; private set; }
        /// <summary>
        /// 前景色
        /// </summary>
        public static Color ForeColor { get; set; }
        /// <summary>
        /// 背景色
        /// </summary>
        public static Color BackgroundColor { get; set; }
      
        
        /// <summary>
        /// 长宽
        /// </summary>
        public static double Width { get; set; }

        public static double Height { get; set; }

        /// <summary>
        /// 真实x,y最大最小坐标
        /// </summary>
        public static double MaxX { get; set; }
        public static double MinX { get; set; }
        public static double MaxY { get; set; }
        public static double MinY { get; set; }

        /// <summary>
        /// 四周各边边距
        /// </summary>
        public static double Top { get; set; }
        public static double Bottom { get; set; }
        public static double Left { get; set; }
        public static double Right { get; set; }

        /// <summary>
        /// 图片类型
        /// </summary>
        public static string GraphicsType { get; set; }

        /// <summary>
        /// 边距
        /// </summary>
        public static double Border { get; set; }

        public static SlogoDrawing Logo { get; set; }
        /// <summary>
        /// 静态初始化
        /// </summary>
        static TurtleCommand()
        {
            X = 0;
            Y = 0;
            H = 0;
            MaxX = 0;
            MinX = 0;
            MaxY = 0;
            MinY = 0;
            IsDrawing = true;
            ForeColor = Color.Black;
            BackgroundColor = Color.White;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public static void Init()
        {
            if(GraphicsType == "png")
            {
                Logo = new PngBitmap(Width, Height);
            }
            else
            {
                Logo = new VectorGraphics(Width, Height);
            }
        }

        /// <summary>
        /// 抬笔
        /// </summary>
        public static void Pu()
        {
            IsDrawing = false;
        }
        /// <summary>
        /// 落笔
        /// </summary>
        public static void Pd()
        {
            IsDrawing = true;
        }
        /// <summary>
        /// 清除所有图形，海龟重置
        /// </summary>
        public static void Cs()
        {
            MaxX = 0;
            MinX = 0;
            MaxY = 0;
            MinY = 0;
            X = 0;
            Y = 0;
            H = 0;
            Logo.Clear(BackgroundColor);
        }
        /// <summary>
        /// 海龟重置
        /// </summary>
        public static void Home()
        {
            X = 0;
            Y = 0;
            H = 0;
        }
        /// <summary>
        /// 海龟沿当前方向前进
        /// </summary>
        /// <param name="displacement">位移</param>
        public static void Fd(double displacement)
        {
            if(IsDrawing)
            {
                if (displacement * Math.Sin(H) > 0)
                {
                    MaxX = ((X + displacement*Math.Sin(H)) < MaxX) ? MaxX : (X + displacement*Math.Sin(H));
                    MinX = (X > MinX) ? MinX : X;
                }
                else
                {
                    MaxX = (X < MaxX) ? MaxX : X;
                    MinX = ((X + displacement * Math.Sin(H)) >MinX) ? MinX : (X + displacement * Math.Sin(H));   
                }
                if (displacement * Math.Cos(H) > 0)
                {
                    MaxY = ((Y + displacement*Math.Cos(H)) < MaxY) ? MaxY : (Y + displacement*Math.Cos(H));
                    MinY = (Y > MinY) ? MinY : Y;
                }
                else
                {
                    MaxY = (Y < MaxY) ? MaxY : Y;
                    MinY = ((Y + displacement * Math.Cos(H)) > MinY) ? MinY : (Y + displacement * Math.Cos(H)); 
                   
                }
                Logo.Line(X, Y, (X + displacement*(Math.Sin(H))), (Y + displacement*(Math.Cos(H))));
            }
            X = X + displacement*(Math.Sin(H));
            Y = Y + displacement*(Math.Cos(H));
        }
        /// <summary>
        /// 海龟沿当前方向后退
        /// </summary>
        /// <param name="displacement">位移</param>
        public static void Bk(double displacement)
        {
            Fd(0 - displacement);
        }
        /// <summary>
        /// 海龟右转
        /// </summary>
        /// <param name="degree">角度</param>
        public static void Rt(double degree)
        {
            H = (H + degree);
        }
        /// <summary>
        /// 海龟左转
        /// </summary>
        /// <param name="degree">角度</param>
        public static void Lt(double degree)
        {
            H = (H - degree);
        }
        /// <summary>
        /// 海龟水平移动
        /// </summary>
        /// <param name="x">水平位置</param>
        public static void SetX(double x)
        {
            if (IsDrawing)
            {
                if (X > x)
                {
                    MaxX = (X < MaxX) ? MaxX : X;
                    MinX = (x > MinX) ? MinX : x;
                }
                else
                {
                    MaxX = (x< MaxY) ? MaxX : x;
                    MinX = (X > MinX) ? MinX : X;
                }
                Logo.Line(X, Y, x,Y);
            }
            X = x;
        }
        /// <summary>
        /// 海龟竖直移动
        /// </summary>
        /// <param name="y">竖直位置</param>
        public static void SetY(double y)
        {
            if (IsDrawing)
            {
                if(Y>y)
                {
                    MaxY = (Y < MaxY) ? MaxY : Y;
                    MinY = (y > MinY) ? MinY : y;
                }
                else
                {
                    MaxY = (y < MaxY) ? MaxY : y;
                    MinY = (Y > MinY) ? MinY : Y;
                }
                Logo.Line(X, Y, X, y);
            }
            Y = y;
        }
        /// <summary>
        /// 海龟移动到新的位置
        /// </summary>
        /// <param name="x">水平位置</param>
        /// <param name="y">竖直位置</param>
        public static void SetXy(double x, double y)
        {
            if (IsDrawing)
            {
                if (X > x)
                {
                    MaxX = (X < MaxX) ? MaxX : X;
                    MinX = (x > MinX) ? MinX : x;
                }
                else
                {
                    MaxX = (x < MaxY) ? MaxX : x;
                    MinX = (X > MinX) ? MinX : X;
                }
                if (Y > y)
                {
                    MaxY = (Y < MaxY) ? MaxY : Y;
                    MinY = (y > MinY) ? MinY : y;
                }
                else
                {
                    MaxY = (y < MaxY) ? MaxY : y;
                    MinY = (Y > MinY) ? MinY : Y;
                }
                Logo.Line(X, Y, x, y);
            }
            X = x;
            Y = y;
        }
        /// <summary>
        /// 设置海龟的朝向
        /// </summary>
        /// <param name="h">绝对角度</param>
        public static void SetH(double h)
        {
            H = h;
        }

        /// <summary>
        /// 以海龟为圆心画指定半径的圆
        /// </summary>
        /// <param name="r">半径</param>
        public static void Circle(double r)
        {
            if (IsDrawing)
            {
                MaxX = (X + r < MaxX) ? MaxX : X + r;
                MinX = (X - r > MinX) ? MinX : X - r;
                MaxY = (Y + r < MaxY) ? MaxY : Y + r;
                MinY = (Y - r > MinY) ? MinY : Y - r;
                Logo.Ellipse(X, Y, 2*r, 2*r,H);
            }
        }

        /// <summary>
        /// 以海龟为圆心画指定半径指定填充色的圆
        /// </summary>
        /// <param name="r">半径</param>
        /// <param name="color">填充色</param>
        public static void CircleFill(double r, int color)
        {
            Color fillcolor = Color.FromArgb(color);
            if (IsDrawing)
            {
                MaxX = (X + r < MaxX) ? MaxX : X + r;
                MinX = (X - r > MinX) ? MinX : X - r;
                MaxY = (Y + r < MaxY) ? MaxY : Y + r;
                MinY = (Y - r > MinY) ? MinY : Y - r;
                Logo.Ellipse(X, Y, 2*r, 2*r,H ,fillcolor);
            }
        }

        /// <summary>
        /// 以海龟为中心，海龟朝向为垂直宽的方向，画指定大小的椭圆
        /// </summary>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        public static void Ellipse(double width, double height)
        {
            if (IsDrawing)
            {
                double diagonal = Math.Sqrt(width*width + height*height);
                MaxX = (X + diagonal / 2 * Math.Sin(H) < MaxX) ? MaxX : X + width / 2;
                MinX = (X - diagonal / 2 * Math.Sin(H) > MinX) ? MinX : X - width / 2;
                MaxY = (Y + diagonal / 2 * Math.Cos(H) < MaxY) ? MaxY : Y + height / 2;
                MinY = (Y - diagonal / 2 * Math.Cos(H) > MinY) ? MinY : Y - height / 2;
                Logo.Ellipse(X, Y, width, height,H);
            }
        }

        /// <summary>
        /// 以海龟为中心，海龟朝向为垂直宽的方向，画指定大小指定填充色的椭圆
        /// </summary>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        /// <param name="color">填充色</param>
        public static void EllipseFill(double width, double height, int color)
        {
            Color fillcolor = Color.FromArgb(color);
            if (IsDrawing)
            {
                double diagonal = Math.Sqrt(width * width + height * height);
                MaxX = (X + diagonal / 2 * Math.Sin(H) < MaxX) ? MaxX : X + width / 2;
                MinX = (X - diagonal / 2 * Math.Sin(H) > MinX) ? MinX : X - width / 2;
                MaxY = (Y + diagonal / 2 * Math.Cos(H) < MaxY) ? MaxY : Y + height / 2;
                MinY = (Y - diagonal / 2 * Math.Cos(H) > MinY) ? MinY : Y - height / 2;
                Logo.Ellipse(X, Y, width, height, H,fillcolor);
            }
        }

        /// <summary>
        /// 以海龟为中心，海龟朝向为垂直宽的方向，画指定大小的矩形
        /// </summary>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        public static void Rect(double width, double height)
        {
            if (IsDrawing)
            {
                double diagonal = Math.Sqrt(width * width + height * height);
                MaxX = (X + diagonal / 2 * Math.Sin(H) < MaxX) ? MaxX : X + width / 2;
                MinX = (X - diagonal / 2 * Math.Sin(H) > MinX) ? MinX : X - width / 2;
                MaxY = (Y + diagonal / 2 * Math.Cos(H) < MaxY) ? MaxY : Y + height / 2;
                MinY = (Y - diagonal / 2 * Math.Cos(H) > MinY) ? MinY : Y - height / 2;
                Logo.Rectangle(X, Y, width, height,H);
            }
        }

        /// <summary>
        /// 以海龟为中心，海龟朝向为垂直宽的方向，画指定大小指定填充色的矩形
        /// </summary>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        /// <param name="color">填充色</param>
        public static void RectFill(double width, double height, int color)
        {
            Color fillcolor = Color.FromArgb(color);
            if (IsDrawing)
            {
                double diagonal = Math.Sqrt(width * width + height * height);
                MaxX = (X + diagonal / 2 * Math.Sin(H) < MaxX) ? MaxX : X + width / 2;
                MinX = (X - diagonal / 2 * Math.Sin(H) > MinX) ? MinX : X - width / 2;
                MaxY = (Y + diagonal / 2 * Math.Cos(H) < MaxY) ? MaxY : Y + height / 2;
                MinY = (Y - diagonal / 2 * Math.Cos(H) > MinY) ? MinY : Y - height / 2;
                Logo.Rectangle(X, Y, width, height, H, fillcolor);
            }
        }

        /// <summary>
        /// 根据坐标点画多边形
        /// </summary>
        /// <param name="num">坐标点</param>
        public static void Poly(double[] num)
        {
            if (IsDrawing)
            {
                PointF[] pointfs = new PointF[num.Length/2];
                for (int i = 0; i < num.Length/2; i++)
                {
                    pointfs[i].X = (float) num[2*i];
                    pointfs[i].Y = (float)num[2 * i + 1];
                    MaxX = (pointfs[i].X < MaxX) ? MaxX : pointfs[i].X;
                    MinX = (pointfs[i].X > MinX) ? MinX : pointfs[i].X;
                    MaxY = (pointfs[i].Y < MaxY) ? MaxY : pointfs[i].Y;
                    MinY = (pointfs[i].Y > MinY) ? MinY : pointfs[i].Y;
                }
                Logo.Polygon(pointfs);
            }
        }

        /// <summary>
        /// 根据坐标点画指定填充色的多边形
        /// </summary>
        /// <param name="num">坐标点</param>
        /// <param name="color">填充色</param>
        public static void PolyFill(double[] num, int color)
        {
            Color fillcolor = Color.FromArgb(color);
            if (IsDrawing)
            {
                PointF[] pointfs = new PointF[num.Length/2];
                for (int i = 0; i < num.Length/2; i++)
                {
                    pointfs[i].X = (float) num[2*i];
                    pointfs[i].Y = (float) num[2*i + 1];
                    MaxX = (pointfs[i].X < MaxX) ? MaxX : pointfs[i].X;
                    MinX = (pointfs[i].X > MinX) ? MinX : pointfs[i].X;
                    MaxY = (pointfs[i].Y < MaxY) ? MaxY : pointfs[i].Y;
                    MinY = (pointfs[i].Y > MinY) ? MinY : pointfs[i].Y;
                }
                Logo.Polygon(pointfs, fillcolor);
            }
        }

        /// <summary>
        /// 设置前景色
        /// </summary>
        /// <param name="color">前景色</param>
        public static void SetFrColor(int color)
        {
            ForeColor = Color.FromArgb(color);
            Logo.SetPenColor(ForeColor);
        }

        /// <summary>
        /// 设置背景色
        /// </summary>
        /// <param name="color">背景色</param>
        public static void SetBkColor(int color)
        {
            BackgroundColor = Color.FromArgb(color);
            Logo.Clear(BackgroundColor);
        }


        /// <summary>
        /// 在图中打印字符串
        /// </summary>
        /// <param name="str"></param>
       public static void Print(string str)
       {
           if (IsDrawing)
           {
               double length = str.Length*16;
               if (length * Math.Sin(H) > 0)
               {
                   MaxX = ((X + length * Math.Sin(H)) < MaxX) ? MaxX : (X + length * Math.Sin(H));
                   MinX = (X > MinX) ? MinX : X;
               }
               else
               {
                   MaxX = (X < MaxX) ? MaxX : X;
                   MinX = ((X + length * Math.Sin(H)) > MinX) ? MinX : (X + length * Math.Sin(H));
               }
               if (length * Math.Cos(H) > 0)
               {
                   MaxY = ((Y + length * Math.Cos(H)) < MaxY) ? MaxY : (Y + length * Math.Cos(H));
                   MinY = (Y > MinY) ? MinY : Y;
               }
               else
               {
                   MaxY = (Y < MaxY) ? MaxY : Y;
                   MinY = ((Y + length * Math.Cos(H)) > MinY) ? MinY : (Y + length * Math.Cos(H));

               }
               Logo.Text(str,H, X, Y);
           }
       }


       /// <summary>
       /// 输出二进制码
       /// </summary>
      public static void WriteOutGraphics()
      {
          if (Top == -1)
          {
              Logo.Print(1000, 1000, Top, Bottom, Left, Right);
          }
          else
          {
              Logo.Print(MaxX - MinX + Left + Right, MaxY - MinY + Top + Bottom, Top, Bottom, Left, Right);
          }
      }
      
      /// <summary>
      /// 输出二进制码(采用真实大小)
      /// </summary>
      public static void WriteOutTrueGraphics()
      {
          Logo.Print(MaxX - MinX + Left + Right, MaxY - MinY + Top + Bottom, Top, Bottom, Left, Right);
      }
    }
}
